import 'dart:async';

import 'package:async/async.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:my_app/base/foundation/flutter_extension.dart';
import 'package:my_app/base/widget/basic/base_gesture.dart';

import '../../foundation/list_value_notifier.dart';

class ReportListWidget extends StatefulWidget {
  final Widget? child;
  final ListValueNotifier? listValueNotifier;

  const ReportListWidget(
      {Key? key, required this.child, this.listValueNotifier})
      : super(key: key);

  @override
  State<ReportListWidget> createState() => _ReportListWidgetState();

  static Stream<ScrollNotification>? of(BuildContext context) {
    return context
        .findAncestorStateOfType<_ReportListWidgetState>()
        ?.broadCaseStream;
  }
}

class _MockScrollMetrics with ScrollMetrics {
  @override
  AxisDirection get axisDirection => AxisDirection.down;

  @override
  double get devicePixelRatio => 0;

  @override
  bool get hasContentDimensions => false;

  @override
  bool get hasPixels => false;

  @override
  bool get hasViewportDimension => false;

  @override
  double get maxScrollExtent => 0;

  @override
  double get minScrollExtent => 0;

  @override
  double get pixels => 0;

  @override
  double get viewportDimension => 0;
}

class _ReportListWidgetState extends State<ReportListWidget> {
  CancelableOperation? _cancellableOperation;
  final _controller = StreamController<ScrollNotification>();
  late final broadCaseStream = _controller.stream.asBroadcastStream();

  @override
  void initState() {
    _postMockScrollNotification();
    widget.listValueNotifier?.addListener(() {
      _postMockScrollNotification();
    });
    super.initState();
  }

  _postMockScrollNotification() {
    _cancellableOperation?.cancel();
    _cancellableOperation = CancelableOperation.fromFuture(
        Future.delayed(const Duration(milliseconds: 500), () {
      if (!mounted) return;
      final scrollNotification = UserScrollNotification(
        metrics: _MockScrollMetrics(),
        context: context,
        direction: ScrollDirection.idle,
      );
      _controller.sink.add(scrollNotification);
    }));
  }

  @override
  Widget build(BuildContext context) {
    return NotificationListener(
      onNotification: (scrollNotification) {
        if (scrollNotification == null) return false;
        if (scrollNotification is! ScrollEndNotification) return false;
        final scrollContext = scrollNotification.context;
        if (scrollContext == null) return false;
        _cancellableOperation?.cancel();
        _cancellableOperation = CancelableOperation.fromFuture(
            Future.delayed(const Duration(milliseconds: 500), () {
          if (!mounted) return;
          _controller.sink.add(scrollNotification);
        }));
        return true;
      },
      child: widget.child ?? const SizedBox(),
    );
  }

  @override
  void dispose() {
    _controller.close();
    _cancellableOperation?.cancel();
    super.dispose();
  }
}

class TDReportCellWidget extends StatefulWidget {
  final Map data;
  final String? localReport;
  final Widget child;
  final Function()? onTap;
  final Function() onShow;

  TDReportCellWidget({
    required this.data,
    this.localReport = '_localReport',
    required this.onShow,
    required this.onTap,
    required this.child,
  }) : super(key: ValueKey('ReportCellWidget#${data.hashCode}'));

  @override
  State<TDReportCellWidget> createState() => _TDReportCellWidgetState();
}

class _TDReportCellWidgetState extends State<TDReportCellWidget> {
  StreamSubscription? _streamSubscription;

  @override
  void initState() {
    if (widget.data[widget.localReport] == true) return;
    final notification = ReportListWidget.of(context);
    _streamSubscription = notification?.listen((event) {
      if (_streamSubscription == null) return;
      final parentRenderBox = event.context?.findRenderObject() as RenderBox?;
      final selfRenderBox = context.findRenderObject() as RenderBox?;
      if (parentRenderBox == null) {
        return;
      } else if (selfRenderBox == null) {
        return;
      }
      final parentBounds = parentRenderBox.paintBounds
          .shift(parentRenderBox.localToGlobal(Offset.zero));
      final selfBounds = selfRenderBox.paintBounds
          .shift(selfRenderBox.localToGlobal(Offset.zero));
      if (parentBounds.containsRect(selfBounds)) {
        widget.data[widget.localReport] = true;
        widget.onShow.call();
        _streamSubscription?.cancel();
        _streamSubscription = null;
      }
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return CommonGestureDetector(
      onTap: widget.onTap,
      child: widget.child,
    );
  }

  @override
  void dispose() {
    _streamSubscription?.cancel();
    super.dispose();
  }
}
